home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / hity wydania / Ubuntu 9.10 PL / karmelkowy-koliberek-9.10-netbook-remix-PL.iso / casper / filesystem.squashfs / usr / share / pyshared / nevow / util.py < prev    next >
Text File  |  2007-08-02  |  7KB  |  232 lines

  1. # Copyright (c) 2004 Divmod.
  2. # See LICENSE for details.
  3.  
  4. import inspect, os.path
  5.  
  6. class UnexposedMethodError(Exception):
  7.     """
  8.     Raised on any attempt to get a method which has not been exposed.
  9.     """
  10.  
  11.  
  12. class Expose(object):
  13.     """
  14.     Helper for exposing methods for various uses using a simple decorator-style
  15.     callable.
  16.  
  17.     Instances of this class can be called with one or more functions as
  18.     positional arguments.  The names of these functions will be added to a list
  19.     on the class object of which they are methods.
  20.  
  21.     @ivar attributeName: The attribute with which exposed methods will be
  22.     tracked.
  23.     """
  24.     def __init__(self, doc=None):
  25.         self.doc = doc
  26.  
  27.  
  28.     def __call__(self, *funcObjs):
  29.         """
  30.         Add one or more functions to the set of exposed functions.
  31.  
  32.         This is a way to declare something about a class definition, similar to
  33.         L{zope.interface.implements}.  Use it like this::
  34.  
  35.         | magic = Expose('perform extra magic')
  36.         | class Foo(Bar):
  37.         |     def twiddle(self, x, y):
  38.         |         ...
  39.         |     def frob(self, a, b):
  40.         |         ...
  41.         |     magic(twiddle, frob)
  42.  
  43.         Later you can query the object::
  44.  
  45.         | aFoo = Foo()
  46.         | magic.get(aFoo, 'twiddle')(x=1, y=2)
  47.  
  48.         The call to C{get} will fail if the name it is given has not been
  49.         exposed using C{magic}.
  50.  
  51.         @param funcObjs: One or more function objects which will be exposed to
  52.         the client.
  53.  
  54.         @return: The first of C{funcObjs}.
  55.         """
  56.         if not funcObjs:
  57.             raise TypeError("expose() takes at least 1 argument (0 given)")
  58.         for fObj in funcObjs:
  59.             fObj.exposedThrough = getattr(fObj, 'exposedThrough', [])
  60.             fObj.exposedThrough.append(self)
  61.         return funcObjs[0]
  62.  
  63.  
  64.     def exposedMethodNames(self, instance):
  65.         """
  66.         Return an iterator of the names of the methods which are exposed on the
  67.         given instance.
  68.         """
  69.         for k, callable in inspect.getmembers(instance, inspect.isroutine):
  70.             if self in getattr(callable, 'exposedThrough', []):
  71.                 yield k
  72.  
  73.  
  74.     _nodefault = object()
  75.     def get(self, instance, methodName, default=_nodefault):
  76.         """
  77.         Retrieve an exposed method with the given name from the given instance.
  78.  
  79.         @raise UnexposedMethodError: Raised if C{default} is not specified and
  80.         there is no exposed method with the given name.
  81.  
  82.         @return: A callable object for the named method assigned to the given
  83.         instance.
  84.         """
  85.         method = getattr(instance, methodName, None)
  86.         exposedThrough = getattr(method, 'exposedThrough', [])
  87.         if self not in getattr(method, 'exposedThrough', []):
  88.             if default is self._nodefault:
  89.                 raise UnexposedMethodError(self, methodName)
  90.             return default
  91.         return method
  92.  
  93.  
  94. def escapeToXML(text, isattrib = False):
  95.     """Borrowed from twisted.xish.domish
  96.  
  97.     Escape text to proper XML form, per section 2.3 in the XML specification.
  98.  
  99.      @type text: L{str}
  100.      @param text: Text to escape
  101.  
  102.      @type isattrib: L{bool}
  103.      @param isattrib: Triggers escaping of characters necessary for use as attribute values
  104.     """
  105.     text = text.replace("&", "&")
  106.     text = text.replace("<", "<")
  107.     text = text.replace(">", ">")
  108.     if isattrib:
  109.         text = text.replace("'", "'")
  110.         text = text.replace("\"", """)
  111.     return text
  112.  
  113.  
  114. def getPOSTCharset(ctx):
  115.     """Locate the unicode encoding of the POST'ed form data.
  116.  
  117.     To work reliably you must do the following:
  118.  
  119.       - set the form's enctype attribute to 'multipart/form-data'
  120.       - set the form's accept-charset attribute, probably to 'utf-8'
  121.       - add a hidden form field called '_charset_'
  122.  
  123.     For instance::
  124.  
  125.       <form action="foo" method="post" enctype="multipart/form-data" accept-charset="utf-8">
  126.         <input type="hidden" name="_charset_" />
  127.         ...
  128.       </form>
  129.     """
  130.  
  131.     from nevow import inevow
  132.  
  133.     request = inevow.IRequest(ctx)
  134.     
  135.     # Try the magic '_charset_' field, Mozilla and IE set this.
  136.     charset = request.args.get('_charset_',[None])[0]
  137.     if charset:
  138.         return charset
  139.  
  140.     # Look in the 'content-type' request header
  141.     contentType = request.received_headers.get('content-type')
  142.     if contentType:
  143.         charset = dict([ s.strip().split('=') for s in contentType.split(';')[1:] ]).get('charset')
  144.         if charset:
  145.             return charset
  146.  
  147.     return 'utf-8'
  148.  
  149.  
  150. from twisted.python.reflect import qual, namedAny, allYourBase, accumulateBases
  151. from twisted.python.util import uniquify
  152.  
  153. from twisted.internet.defer import Deferred, succeed, maybeDeferred, DeferredList
  154. from twisted.python import failure
  155. from twisted.python.failure import Failure
  156. from twisted.python import log
  157.  
  158.  
  159. ## The tests rely on these, but they should be removed ASAP
  160. def remainingSegmentsFactory(ctx):
  161.     return tuple(ctx.tag.postpath)
  162.  
  163.  
  164. def currentSegmentsFactory(ctx):
  165.     return tuple(ctx.tag.prepath)
  166.  
  167. class _RandomClazz(object):
  168.     pass
  169. class _NamedAnyError(Exception):
  170.     'Internal error for when importing fails.'
  171.  
  172. def _namedAnyWithBuiltinTranslation(name):
  173.     if name == '__builtin__.function':
  174.         name='types.FunctionType'
  175.     elif name == '__builtin__.method':
  176.         return _RandomClazz # Hack
  177.     elif name == '__builtin__.instancemethod':
  178.         name='types.MethodType'
  179.     elif name == '__builtin__.NoneType':
  180.         name='types.NoneType'
  181.     elif name == '__builtin__.generator':
  182.         name='types.GeneratorType'
  183.     return namedAny(name)
  184.  
  185. # Import resource_filename from setuptools's pkg_resources module if possible
  186. # because it handles resources in .zip files. If it's not provide a version
  187. # that assumes the resource is directly available on the filesystem. 
  188. try:
  189.     from pkg_resources import resource_filename
  190. except ImportError:
  191.     def resource_filename(modulename, resource_name):
  192.         modulepath = namedAny(modulename).__file__
  193.         return os.path.join(os.path.dirname(os.path.abspath(modulepath)), resource_name)
  194.  
  195.  
  196.  
  197. class CachedFile(object):
  198.     """
  199.     Helper for caching operations on files in the filesystem.
  200.     """
  201.     def __init__(self, path, loader):
  202.         """
  203.         @type path: L{str}
  204.         @param path: The path to the associated file in the filesystem.
  205.  
  206.         @param loader: A callable that returns the relevant data; invoked when
  207.         the cache is empty or stale.
  208.         """
  209.  
  210.         self.path = path
  211.         self.loader = loader
  212.         self.invalidate()
  213.  
  214.     def invalidate(self):
  215.         """
  216.         Invalidate the cache, forcing a reload from disk at the next attempted
  217.         load.
  218.         """
  219.         self._mtime = None
  220.  
  221.     def load(self, *args, **kwargs):
  222.         """
  223.         Load this file. Any positional or keyword arguments will be passed
  224.         along to the loader callable, after the path itself.
  225.         """
  226.         currentTime = os.path.getmtime(self.path)
  227.         if self._mtime is None or currentTime != self._mtime:
  228.             self._cachedObj = self.loader(self.path, *args, **kwargs)
  229.             self._mtime = currentTime
  230.  
  231.         return self._cachedObj
  232.